import type { IManager, ManagerOptions } from '../index.d';
import EventEmitter from './event';

export class Base<E> {
  protected managers: Map<string, IManager> = new Map();

  protected emitter = new EventEmitter<Record<string, [string, IManager]>>();

  // TODO event + extraKey 来监听可以实现细粒度的通知
  onManaAdd = (handler: (...payload: [string, IManager]) => void) => {
    this.emitter.on('managerAdd', handler);
    return this;
  };

  onManaRemove = (handler: (...payload: [string, IManager]) => void) => {
    this.emitter.off('managerRemove', handler);
    return this;
  };

  // 添加use方法
  public use<T extends IManager>(
    Manager: new (base: E, options?: ManagerOptions) => T,
    name?: string, // 可选的组件名参数，默认为类的name
    options?: ManagerOptions,
  ): T {
    const key = name || Manager.name;

    // 重复注册检查
    if (this.managers.has(key)) {
      // TODO console.warn(`Manager ${key} already registered`);
      return this.managers.get(key) as T;
    }

    const manager = new Manager(this as unknown as E, options);
    this.managers.set(key, manager);
    name && this.emitter.emit('managerAdd', name, manager);
    return manager;
  }

  public attach = this.use;

  /**
   * 获取已注册的manager实例
   * @param Manager manager类
   * @param name 可选名称，默认为类名
   * @returns manager实例或undefined
   */
  public get<T extends IManager>(
    Manager: new (base: E, options?: ManagerOptions) => T,
    name?: string,
  ): T | undefined {
    const key = name || Manager.name;
    return this.managers.get(key) as T | undefined;
  }

  /**
   * 获取已注册的manager实例
   * @param name 可选名称，默认为类名
   * @returns manager实例或undefined
   */
  public getByName<T extends IManager>(name: string): T | undefined {
    return this.managers.get(name) as T | undefined;
  }

  // 添加组件卸载方法
  public unuse<T extends IManager>(
    Manager: new (base: E, options?: ManagerOptions) => T,
    name?: string,
  ): boolean {
    const key = name || Manager.name;
    const manager = this.managers.get(key);

    if (manager) {
      // 调用管理器的清理方法（如果存在）
      if ('destroy' in manager) {
        (manager as IManager).destroy();
      }
      this.managers.delete(key);

      name && this.emitter.emit('managerRemove', name, manager);

      return true;
    }
    return false;
  }

  public detach = this.unuse;

  public clear() {
    this.managers.forEach((manager) => {
      if ('destroy' in manager) {
        (manager as IManager).destroy();
      }
    });
    this.managers.clear();
  }
}
